package com.ruoyi.business.listener;

import com.alibaba.fastjson.JSON;
import com.ruoyi.business.constant.TradeConstants;
import com.ruoyi.business.domain.BusinessTradeRecord;
import com.ruoyi.business.dto.TicketDTO;
import com.ruoyi.business.enumType.PSIceOrderType;
import com.ruoyi.business.enumType.TriggerType;
import com.ruoyi.business.service.IBusinessTradeRecordService;
import com.ruoyi.business.service.OnTicketHandler;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 当存在首次亏损情况下，根据实时行情自动下单，做空或者做多
 */
@Component("autoOrderSubscriber")
public class AutoOrderSubscriber implements OnTicketHandler {


    /**
     * 日志
     */
    private static final Logger logger = LoggerFactory.getLogger(AutoOrderSubscriber.class);
    @Autowired
    private IBusinessTradeRecordService businessTradeRecordService;


    @Autowired
    private RedisCache redisCache;
    /**
     * @param message
     */
    @Override
    public synchronized void onTicket(String message) {
        logger.info("再次开仓监听，message:{}", message);
        List<TicketDTO> ticketDTOS = JSON.parseArray(message, TicketDTO.class);
        TicketDTO ticketDTO = ticketDTOS.get(0);
        BigDecimal price =  new BigDecimal(String.valueOf(ticketDTO.getPrice()));
        Date marketTime = ticketDTO.getMarketTime();
        BigDecimal open = redisCache.getCacheObject(TradeConstants.SYMBOL_PRICE_OPEN_KEY + DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD, marketTime));




        if (price.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        try {
            List<BusinessTradeRecord> businessTradeRecordList = businessTradeRecordService.selectTodayTradeRecord();
            if (businessTradeRecordList.isEmpty()) {
                return;
            }
            Map<Long, List<BusinessTradeRecord>> strategyRecordMap = businessTradeRecordList.stream().collect(Collectors.groupingBy(BusinessTradeRecord::getStrategyId));
            strategyRecordMap.forEach((strategyId, strategyRecordList) -> {
                // 对止损单或者止损单 并且未再次开仓过的进行开仓
                strategyRecordList = strategyRecordList.stream().filter(item -> 1 == item.getTradingStatus())
                        .filter(item -> !item.getHasLoseOpened()).collect(Collectors.toList());
                // 相同委托编号的为一个仓
                Map<String, List<BusinessTradeRecord>> positionProfitRecord = strategyRecordList.stream().filter(item -> item.getTriggerType().equals(TriggerType.DYNAMIC_STOP_PROFIT_TRIGGER.toString()) || item.getTriggerType().equals(TriggerType.STATIC_STOP_PROFIT_TRIGGER.toString())).collect(Collectors.groupingBy(BusinessTradeRecord::getDelegateCode));
                Map<String, List<BusinessTradeRecord>> positionLossRecord = strategyRecordList.stream().filter(item -> item.getTriggerType().equals(TriggerType.STATIC_STOP_LOSS_TRIGGER.toString())).collect(Collectors.groupingBy(BusinessTradeRecord::getDelegateCode));


                // 针对每个仓进行再次开仓 ，盈利的，方向相反
                for (Map.Entry<String, List<BusinessTradeRecord>> profitEntry : positionProfitRecord.entrySet()) {
                    // 再次开仓过的仓，标识，不在再次开仓
                    List<BusinessTradeRecord> value = profitEntry.getValue();
                    boolean b = value.stream().allMatch(BusinessTradeRecord::getHasLoseOpened);
                    if (b) {
                        continue;
                    }
                    Integer delegateType = value.get(0).getDelegateType();
                    String clientName = value.get(0).getClientName();
                    String password = value.get(0).getPassword();


                    if (PSIceOrderType.Sell.equals(PSIceOrderType.valueOf(delegateType))) {
                        delegateType = PSIceOrderType.Buy.value();
                    }
                    AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeAuto(strategyId, PSIceOrderType.valueOf(delegateType), price, open, ticketDTO.getSymbol(), false, null);
                    int code = (int) ajaxResult.get(AjaxResult.CODE_TAG);
                    if (code == 200) {
                        updateReopenSymbolBatch(value);
                        logger.info("止盈单再次开仓成功，委托数据：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                    } else {
                        logger.error("止盈单再次开仓失败,msg:{}", ajaxResult.get(AjaxResult.MSG_TAG));
                    }
                }

                // 针对每个仓进行再次开仓，亏损的方向相同
                for (Map.Entry<String, List<BusinessTradeRecord>> lossEntry : positionLossRecord.entrySet()) {
                    // 再次开仓过的仓，标识，不在再次开仓
                    List<BusinessTradeRecord> value = lossEntry.getValue();
                    boolean b = value.stream().allMatch(BusinessTradeRecord::getHasLoseOpened);
                    if (b) {
                        continue;
                    }
                    Integer delegateType = value.get(0).getDelegateType();
                    AjaxResult ajaxResult = businessTradeRecordService.doBusinessTradeAuto(strategyId, PSIceOrderType.valueOf(delegateType), price, open, ticketDTO.getSymbol(), false, null);
                    int code = (int) ajaxResult.get(AjaxResult.CODE_TAG);
                    if (code == 200) {
                        updateReopenSymbolBatch(value);
                        logger.info("止损单再次开仓成功，委托数据：{}", JSON.toJSONString(ajaxResult.get(AjaxResult.DATA_TAG)));
                    } else {
                        logger.error("止损单再次开仓失败,msg:{}", ajaxResult.get(AjaxResult.MSG_TAG));
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("再次开仓出错：", e);
        }
    }

    private void updateReopenSymbolBatch(List<BusinessTradeRecord> value) {
        for (BusinessTradeRecord businessTradeRecord : value) {
            businessTradeRecord.setHasLoseOpened(true);
            businessTradeRecordService.updateBusinessTradeRecord(businessTradeRecord);
        }
    }
}

